#include "sdk.h"
#include "M_Code_auibook.h"
#include "ThreadSearchThread.h"
#include "ThreadSearchEvent.h"
#include "TextFileSearcher.h"

ThreadSearchThread::ThreadSearchThread( ThreadSearchView* pThreadSearchView, const ThreadSearchFindData& findData ) {
  m_pThreadSearchView = pThreadSearchView;
  m_FindData = findData;
  m_DefaultDirResult  = ( findData.GetRecursiveSearch() == true ) ? wxDIR_CONTINUE : wxDIR_IGNORE;
  m_Masks = GetArrayFromString( m_FindData.GetSearchMask() );
  if( m_Masks.GetCount() == 0 ) {
    m_Masks.Add( _T( "*" ) );
  }
  m_pTextFileSearcher = TextFileSearcher::BuildTextFileSearcher( findData.GetFindText(), findData.GetMatchCase(),
                        findData.GetStartWord(), findData.GetMatchWord(), findData.GetRegEx() );
  if( !m_pTextFileSearcher ) {
    ThreadSearchEvent event( wxEVT_THREAD_SEARCH_ERROR, -1 );
    event.SetString( _T( "TextFileSearcher 无法实例化" ) );
    wxPostEvent( m_pThreadSearchView, event );
  }
  ConfigManager* pCfg = Manager::Get()->GetConfigManager( _T( "ThreadSearch" ) );
  m_ShowFileMissingError = pCfg->ReadBool( _T( "/ShowFileMissingError" ), true );
  m_ShowCantOpenFileError = pCfg->ReadBool( _T( "/ShowCantOpenFileError" ), true );
}

ThreadSearchThread::~ThreadSearchThread() {
  if( m_pTextFileSearcher != NULL ) {
    delete m_pTextFileSearcher;
  }
}

void *ThreadSearchThread::Entry() {
  if( m_pTextFileSearcher == NULL ) {
    return 0;
  }
  size_t i = 0;
  if( m_FindData.MustSearchInDirectory() == true ) {
    int flags = wxDIR_FILES | wxDIR_DIRS | wxDIR_DOTDOT;
    flags |= m_FindData.GetHiddenSearch() ? wxDIR_HIDDEN : 0;
    const wxString &path = m_FindData.GetSearchPath( true );
    if( !wxDir::Exists( path ) ) {
      ThreadSearchEvent event( wxEVT_THREAD_SEARCH_ERROR, -1 );
      event.SetString( _T( "无法打开文件夹 " ) + path );
      wxPostEvent( m_pThreadSearchView, event );
      return 0;
    } else {
      wxDir Dir( path );
      Dir.Traverse( *( static_cast<wxDirTraverser*>( this ) ), wxEmptyString, flags );
    }
    if( TestDestroy() == true ) {
      return 0;
    }
  }
  if( m_FindData.MustSearchInWorkspace() == true ) {
    ProjectsArray* pProjectsArray = Manager::Get()->GetProjectManager()->GetProjects();
    for( size_t j = 0; j < pProjectsArray->GetCount(); ++j ) {
      AddProjectFiles( m_FilePaths, *pProjectsArray->Item( j ) );
      if( TestDestroy() == true ) {
        return 0;
      }
    }
  } else if( m_FindData.MustSearchInProject() == true ) {
    M_Code_Project* pProject = Manager::Get()->GetProjectManager()->GetActiveProject();
    if( pProject != NULL ) {
      AddProjectFiles( m_FilePaths, *pProject );
      if( TestDestroy() == true ) {
        return 0;
      }
    }
  } else if( m_FindData.MustSearchInTarget() == true ) {
    M_Code_Project* pProject = Manager::Get()->GetProjectManager()->GetActiveProject();
    if( pProject != NULL ) {
      ProjectBuildTarget *pTarget = pProject->GetBuildTarget( pProject->GetActiveBuildTarget() );
      if( pTarget != 0 ) {
        AddTargetFiles( m_FilePaths, *pTarget );
        if( TestDestroy() == true ) {
          return 0;
        }
      }
    }
  }
  if( TestDestroy() == true ) {
    return 0;
  }
  if( m_FindData.MustSearchInOpenFiles() == true ) {
    EditorManager* pEdManager = Manager::Get()->GetEditorManager();
    for( i = 0; i < ( size_t )pEdManager->GetNotebook()->GetPageCount(); ++i ) {
      M_Code_Editor* pEditor = pEdManager->GetBuiltinEditor( i );
      if( pEditor != NULL ) {
        AddNewItem( m_FilePaths, pEditor->GetFilename() );
      }
    }
  }
  if( TestDestroy() == true ) {
    return 0;
  }
  if( m_FilePaths.GetCount() == 0 ) {
    ThreadSearchEvent event( wxEVT_THREAD_SEARCH_ERROR, -1 );
    event.SetString( _T( "没有要搜索的文件 请检查选项 " ) );
    wxPostEvent( m_pThreadSearchView, event );
    return 0;
  }
  for( i = 0; i < m_FilePaths.GetCount(); ++i ) {
    FindInFile( m_FilePaths[i] );
    if( TestDestroy() == true ) {
      return 0;
    }
  }
  return 0;
}

void ThreadSearchThread::OnExit() {
  m_pThreadSearchView->OnThreadExit();
}

wxDirTraverseResult ThreadSearchThread::OnDir( const wxString& dirName ) {
  if( TestDestroy() == true ) {
    return wxDIR_STOP;
  }
  wxString path = cbResolveSymLinkedDirPathRecursive( dirName );
  if( m_VisitedDirs.find( path ) != m_VisitedDirs.end() ) {
    return wxDIR_IGNORE;
  }
  m_VisitedDirs.insert( path );
  return m_DefaultDirResult;
}

wxDirTraverseResult ThreadSearchThread::OnFile( const wxString& fileName ) {
  if( TestDestroy() == true ) {
    return wxDIR_STOP;
  }
  for( size_t i = 0; i < m_Masks.GetCount(); ++i ) {
    if( fileName.Matches( m_Masks[i].c_str() ) ) {
      m_FilePaths.Add( fileName );
      break;
    }
  }
  return wxDIR_CONTINUE;
}

void ThreadSearchThread::FindInFile( const wxString& path ) {
  m_LineTextArray.Empty();
  switch( m_pTextFileSearcher->FindInFile( path, m_LineTextArray ) ) {
    case TextFileSearcher::idStringFound: {
      ThreadSearchEvent event( wxEVT_THREAD_SEARCH, -1 );
      event.SetString( path );
      event.SetLineTextArray( m_LineTextArray );
      m_pThreadSearchView->PostThreadSearchEvent( event );
      break;
    }
    case TextFileSearcher::idStringNotFound:
      break;
    case TextFileSearcher::idFileNotFound: {
      if( m_ShowFileMissingError ) {
        ThreadSearchEvent event( wxEVT_THREAD_SEARCH_ERROR, -1 );
        event.SetString( path + _T( " 不存在 " ) );
        wxPostEvent( m_pThreadSearchView, event );
      }
      break;
    }
    case TextFileSearcher::idFileOpenError: {
      if( m_ShowCantOpenFileError ) {
        ThreadSearchEvent event( wxEVT_THREAD_SEARCH_ERROR, -1 );
        event.SetString( _T( "打开失败 " ) + path );
        wxPostEvent( m_pThreadSearchView, event );
      }
      break;
    }
    default:
    { }
  }
}

bool ThreadSearchThread::AddNewItem( wxSortedArrayString& sortedArrayString, const wxString& newItem ) {
  bool added = false;
  if( sortedArrayString.Index( newItem.c_str() ) == wxNOT_FOUND ) {
    sortedArrayString.Add( newItem );
    added = true;
  }
  return added;
}

void ThreadSearchThread::AddProjectFiles( wxSortedArrayString& sortedArrayString, M_Code_Project& project ) {
  for( FilesList::iterator it = project.GetFilesList().begin(); it != project.GetFilesList().end(); ++it ) {
    AddNewItem( sortedArrayString, ( *it )->file.GetFullPath() );
    if( TestDestroy() == true ) {
      return;
    }
  }
}

void ThreadSearchThread::AddTargetFiles( wxSortedArrayString& sortedArrayString, ProjectBuildTarget& target ) {
  for( FilesList::iterator it = target.GetFilesList().begin(); it != target.GetFilesList().end(); it++ ) {
    ProjectFile* pf = *it;
    AddNewItem( sortedArrayString, pf->file.GetFullPath() );
    if( TestDestroy() == true ) {
      return;
    }
  }
}
